package org.opensuse.bs.ui.views;

import java.io.File;
import java.util.Vector;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.DrillDownAdapter;
import org.eclipse.ui.part.ViewPart;
import org.opensuse.bs.ui.BSUIPlugin;
import org.opensuse.bs.ui.IBSUIConstants;
import org.opensuse.bs.ui.OSC;
import org.opensuse.bs.ui.actions.CheckoutAction;
import org.opensuse.bs.ui.actions.SearchAction;
import org.opensuse.bs.ui.model.BSModelElement;
import org.opensuse.bs.ui.model.DecoratingRemoteLabelProvider;
import org.opensuse.bs.ui.model.RemoteContentProvider;
import org.opensuse.bs.ui.model.RootElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class RemoteView extends ViewPart{
	private TreeViewer viewer;
	
	private Action refreshAction;
	private Action collapseAllAction;
	private CheckoutAction checkoutAction;
	private SearchAction searchAction;
	private Action addToWatchAction;
	private Action removeFromWatchAction;
	private Action listWatchlistAction;
	private Action listAllAction;
	private DrillDownAdapter drillPart;
	
	private void refresh() {
		if (viewer == null) {
			return;
		}
       viewer.getControl().setRedraw(false);
       viewer.refresh();
       viewer.getControl().setRedraw(true);
	}
	
	private void collapseAll() {
		if (viewer == null) {
			return;
		}
		viewer.getControl().setRedraw(false);
		viewer.collapseToLevel(viewer.getInput(), AbstractTreeViewer.ALL_LEVELS);
		viewer.getControl().setRedraw(true);
	}
	
	private void remove() {
		if(viewer == null)
			return;
		if(!MessageDialog.openQuestion(
				null, 
				"Delete from watchlist", 
				"Are you really sure?")
				)return;
		ITreeSelection node = (ITreeSelection) viewer.getSelection();
		if(node.size() == 0)return;
		final TreePath[] paths = node.getPaths();
		viewer.remove(paths);
		final String user = BSUIPlugin.getDefault().getUser();
		Job removeFromWatchJob = new Job("Remove from Watchlist") {
			public IStatus run(IProgressMonitor monitor) {
				try {
					Document doc = OSC.toXML("req /person/"+user);
					if(doc == null) {
						return Status.CANCEL_STATUS;
					}
					Element watchList = (Element) doc.getElementsByTagName("watchlist").item(0);
					NodeList prjList = watchList.getElementsByTagName("project");
					for(TreePath path: paths) {
						BSModelElement o = (BSModelElement) path.getFirstSegment();
						String aim = o.getName();
						for(int i=0;i<prjList.getLength();i++) {
							Element one = (Element) prjList.item(i);
							if(one.getAttribute("name").equals(aim)) {
								watchList.removeChild(one);
								break;
							}
						}
					}
					File file = OSC.toFile(doc, "WatchList");
					Vector<String> result = OSC.run("req -m PUT -f "+file.getAbsolutePath()+" /person/"+user);
					file.delete();
					if(result.isEmpty()) {
						return Status.CANCEL_STATUS;
					}
				}catch(Exception e) {
					e.printStackTrace();
				}
				if(monitor.isCanceled())
					return Status.CANCEL_STATUS;
				return Status.OK_STATUS;
			}
		};
		removeFromWatchJob.schedule();
	}
	
	public void add() {
		if(viewer == null)
			return;
		ITreeSelection node = (ITreeSelection) viewer.getSelection();
		if(node.size() == 0) return;
		final TreePath[] paths = node.getPaths();
		final String user = BSUIPlugin.getDefault().getUser();
		Job addWatchJob = new Job("Add to Watchlist") {
			protected IStatus run(IProgressMonitor monitor) {
				try {
					Document doc = OSC.toXML("req /person/"+user);
					if(doc == null) {
						return Status.CANCEL_STATUS;
					}
					NodeList list = doc.getElementsByTagName("watchlist");
					if(list.getLength()==0) {
						Element watchList = doc.createElement("watchlist");
						for(TreePath path : paths) {
							String prj = ((BSModelElement) path.getFirstSegment()).getName();
							Element one = doc.createElement("project");
							one.setAttribute("name", prj);
							watchList.appendChild(one);
						}
					}
					else {
						Element watchList = (Element) list.item(0);
						NodeList prjList = watchList.getElementsByTagName("project");
						for(TreePath path : paths) {
							String prj = ((BSModelElement) path.getFirstSegment()).getName();
							boolean has = false;
							for(int i=0;i<prjList.getLength();i++) {
								Element tmp = (Element) prjList.item(i);
								if(tmp.getAttribute("name").equals(prj)) {
									has = true;
									break;
								}
							}
							if(has)continue;
							Element one = doc.createElement("project");
							one.setAttribute("name", prj);
							watchList.appendChild(one);
						}
					}
					
					final File file = OSC.toFile(doc, "Watchlist");
					Vector<String> result = OSC.run("req -m PUT -f "+file.getAbsolutePath()+" /person/"+user);
					file.delete();
					if(result.isEmpty()) {
						return Status.CANCEL_STATUS;
					}
				}catch(Exception e) {
					e.printStackTrace();
				}
				if(monitor.isCanceled())
					return Status.CANCEL_STATUS;
				return Status.OK_STATUS;
			}
		};
		addWatchJob.schedule();
	}
	
	private void addWorkbenchActions(IMenuManager manager) {
		manager.add(new Separator(IWorkbenchActionConstants.GROUP_FILE));
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
		manager.add(refreshAction);
		manager.add(checkoutAction);
		manager.add(addToWatchAction);
		manager.add(removeFromWatchAction);
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
	}
	
	private void createActions() {
		BSUIPlugin plugin = BSUIPlugin.getDefault();
		refreshAction = new Action("&Refresh View", BSUIPlugin.getDefault().getImageDescriptor(IBSUIConstants.IMG_REFRESH_ENABLED)) {
			public void run() {
				refresh();
			}
		};
		refreshAction.setToolTipText("Refresh View");
		refreshAction.setDisabledImageDescriptor(plugin.getImageDescriptor(IBSUIConstants.IMG_REFRESH_DISABLED));
		refreshAction.setHoverImageDescriptor(plugin.getImageDescriptor(IBSUIConstants.IMG_REFRESH));
		getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.REFRESH.getId(), refreshAction);
		
		collapseAllAction = new Action("Collapse All") {
			public void run() {
				collapseAll();
			}
		};
		collapseAllAction.setToolTipText("Collapse All");
		collapseAllAction.setHoverImageDescriptor(plugin.getImageDescriptor(IBSUIConstants.IMG_COLLAPSE_ALL));
		
		checkoutAction = new CheckoutAction(viewer, "Check Out");
		
		removeFromWatchAction = new Action("Remove from Watchlist") {
			public void run() {
				remove();
			}
		};
		removeFromWatchAction.setEnabled(false);
		
		addToWatchAction = new Action("Add to Watchlist") {
			public void run() {
				add();
			}
		};
		
		listAllAction = new Action("List All") {
			public void run() {
				viewer.setInput(new RootElement(1));
				addToWatchAction.setEnabled(true);
				removeFromWatchAction.setEnabled(false);
			}
		};
		listAllAction.setHoverImageDescriptor(plugin.getImageDescriptor(IBSUIConstants.IMG_LIST_ALL));
		
		listWatchlistAction = new Action("Watchlist") {
			public void run() {
				String user = BSUIPlugin.getDefault().getUser(); 
				if(user.length() == 0) {
					MessageDialog.openWarning(null, "Lack of user name", 
							"Please use File-->New-->Project-->Build Service/Connection Wizard " +
							"to supply default api and user");
					return;
				}
				viewer.setInput(new RootElement(0));
				addToWatchAction.setEnabled(false);
				removeFromWatchAction.setEnabled(true);
			}
		};
		listWatchlistAction.setHoverImageDescriptor(plugin.getImageDescriptor(IBSUIConstants.IMG_LIST_WATCHlIST));
		
		searchAction = new SearchAction(viewer, this);
	}
	
	private void createMenu() {
		IMenuManager manager = getViewSite().getActionBars().getMenuManager();
		manager.add(checkoutAction);
		manager.add(addToWatchAction);
		manager.add(removeFromWatchAction);
		manager.add(searchAction);
	}
	
	private void createToolbar() {
		IActionBars bars = getViewSite().getActionBars();
		IToolBarManager tbm = bars.getToolBarManager();
		drillPart.addNavigationActions(tbm);
		tbm.add(refreshAction);
		tbm.add(new Separator());
		tbm.add(collapseAllAction);
		tbm.add(new Separator());
		tbm.add(listAllAction);
		tbm.add(listWatchlistAction);
		tbm.update(false);
		bars.updateActionBars();
	}
	
	private void createContextMenu() {
		MenuManager mm = new MenuManager();
		Tree t = viewer.getTree();
		Menu m = mm.createContextMenu(t);
		mm.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				addWorkbenchActions(manager);
			}
		});
		mm.setRemoveAllWhenShown(true);
		t.setMenu(m);
		getSite().registerContextMenu(mm, viewer);
	}
	
	public void createPartControl(Composite parent) {
		viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		viewer.setContentProvider(new RemoteContentProvider());
		viewer.setLabelProvider(new DecoratingRemoteLabelProvider());
		getSite().setSelectionProvider(viewer); //Providing selection event
		viewer.setInput(new RootElement(1));
		viewer.getControl().addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent event) {
				if(event.keyCode == SWT.F5) {
					refresh();
				}
			}
		});
		viewer.getControl().addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent event) {
				if(event.stateMask == SWT.CTRL && event.keyCode == 'f') {
					searchAction.run();
				}
			}
		});
		drillPart = new DrillDownAdapter(viewer);
		
		createActions();
		createMenu();
		createToolbar();
		createContextMenu();
	}

	public Action getAddToWatchListAction() {
		return this.addToWatchAction;
	}
	
	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	public void dispose() {
		super.dispose();
		viewer = null;
	}

}
